package com.fingard.net.niosocket;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;

import com.fingard.diagnostics.LogHelper;

public abstract class NioReceiver {

	/**连接开始时间*/
	public Date connTime;

	public byte[] recBytes;
    
    public int contentLength ;
    public int contentStartIndex ;
   
    public int readedLength;

    /**默认字符集*/
	protected String defCharset = "gbk";
	
    public long seqIDInner;

    public String sourceIP;
    public int receiveOffSet;
    
    public int readHeadStartIndex;
    
    /**接收是否结束*/
    public boolean isFinished;
    
    /**接收结束时间*/
	public Date finishTime;
    
    public boolean hasError;
    public String errMsg;
    
    public SocketChannel clientSocketChannel;
	
    public NioReceiver(SocketChannel p_socketChannel, String p_defCharset) {
    	clientSocketChannel = p_socketChannel;
    	defCharset = p_defCharset;
    	reset();
	}
    
    public void reset(){
    	contentLength = -1;
    	contentStartIndex = -1;
    	readedLength = 0;
    	receiveOffSet = 0;
    	readHeadStartIndex = 0;
    	isFinished = false;
    	hasError = false;
    	errMsg = "";
    }
    
    public abstract void getHeader() throws UnsupportedEncodingException;
    
    public ByteBuffer recByteBuffer;
    
    /**接收字节*/
    public void receiveBytes(){
		try {
			if(recByteBuffer == null){
				recBytes = new byte[2048];//2K
	    		recByteBuffer = ByteBuffer.wrap(recBytes);
	    	}
	    	int tmpReadLen = clientSocketChannel.read(recByteBuffer);
			if (tmpReadLen <= 0) {
				decideFinished(tmpReadLen);
				return;
	        }
			
			readedLength += tmpReadLen;
			receiveOffSet += tmpReadLen;
			if(contentLength < 0){
				getHeader();
			}
            if (contentLength > 0 && contentStartIndex >= 0) {
            	if (recBytes.length < contentLength + contentStartIndex) {
                    byte[] tmpUnionInfo = new byte[contentLength + contentStartIndex];//一次性分配内存
                    recByteBuffer = ByteBuffer.wrap(tmpUnionInfo);
                    recByteBuffer.put(recBytes, 0, receiveOffSet);
                    recBytes = null;
                    recBytes = tmpUnionInfo;
                }
            }
            decideFinished(tmpReadLen);
            
		} catch(Throwable e){
			hasError = true;
			isFinished = true;
			finishTime = new Date();
			errMsg = LogHelper.getStackTraceFirstLine(e);
		}
    }
    
    public void decideFinished(int p_readLen){
    	if(hasError){
    		isFinished = true;
    	}
    	else if (contentLength == 0){
        	isFinished = true;
        }else{
        	if(p_readLen <= 0){
        		isFinished = true;
        	}
        	if(contentLength > 0){
        		int tmpToReadLen = contentLength + contentStartIndex - readedLength;
                if (tmpToReadLen == 0) {//完成
                	isFinished = true;
                }else if(tmpToReadLen < 0 || (p_readLen == 0 && tmpToReadLen != 0)){//结束
                	isFinished = true;
                	int expectLen = contentLength + contentStartIndex;
                	int actualLen = readedLength - contentStartIndex;
                	errMsg = "实际接收总字节数"+readedLength+"与预期"+expectLen+"不符，其中实际接收内容字节数"+actualLen+"，预期内容字节数"+contentLength;
                	hasError = true;
                }
        	}
        }
        if(isFinished){
        	finishTime = new Date();
    	}
    }
    
    /**是否结束读取请求字节*/
    public boolean isStopRead(){
    	if(isFinished || hasError){
    		return true;
    	}
    	return false;
    }
    
    public String getRawReqStr() throws UnsupportedEncodingException{
    	return new String(recBytes,0,readedLength,defCharset);
    }
    
    public String getReqBodyContent() throws UnsupportedEncodingException{
    	if(readedLength-contentStartIndex > 0){
    		return new String(recBytes,this.contentStartIndex,readedLength-contentStartIndex,defCharset);
    	}else{
    		return "";
    	}
    }
}
